package com.symaster.common.connect.v3.util;

import com.symaster.common.connect.v3.api.AcceptListener;
import com.symaster.common.connect.v3.config.SocketConfig;
import com.symaster.common.connect.v3.core.ID;
import com.symaster.common.connect.v3.socket.TcpServer;

import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;

/**
 * @author yinmiao
 * @version 2024/1/2
 */
public class SocketDataUtil implements AcceptListener {

    private final TcpServer tcpServer;
    private final Map<ID, Socket> socketMap;
    private final Map<ID, Object> treeLockMap;

    private final Map<UUID, Object> sessionMap;

    public static void main(String[] args) {

        // UUID uuid = UUID.randomUUID();


        for (int i = 0; i < 5; i++) {
            double s = System.nanoTime() / 1000000.0;
            UUID uuid1 = UUID.randomUUID();
            String string = uuid1.toString();

            // byte[] bytes = string.getBytes(StandardCharsets.UTF_8);

            double e = System.nanoTime() / 1000000.0;

            // System.out.println(bytes.length);
            System.out.printf("%.6f%n", e - s);
        }


    }

    public SocketDataUtil(TcpServer tcpServer) {
        this.tcpServer = tcpServer;
        this.socketMap = new Hashtable<>();
        this.treeLockMap = new Hashtable<>();
        this.sessionMap = new Hashtable<>();
        this.tcpServer.setAcceptListener(this);
    }

    private void write(ID id, byte[] bytes) {
        UUID sessionId = randomSessionId();
        sessionMap.put(sessionId, new Object());

        synchronized (sessionMap.get(sessionId)) {
            synchronized (treeLockMap.get(id)) {

                try {
                    socketMap.get(id).getOutputStream().write(bytes);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            try {
                sessionMap.get(sessionId).wait(SocketConfig.timeout);
            } catch (InterruptedException ignored) {
            }
        }
    }

    private UUID randomSessionId() {
        do {
            UUID uuid = UUID.randomUUID();
            if (!sessionMap.containsKey(uuid)) {
                return uuid;
            }
        } while (true);
    }

    @Override
    public void accept(Socket socket) {
        ID id = new ID();
        socketMap.put(id, socket);
        treeLockMap.put(id, new Object());
        write(id, id.toString().getBytes(StandardCharsets.UTF_8));
    }
}
